

#include <cstddef>
#include <memory>
#include <optional>
#include <vector>

/*/////////////////no template
class GamePiece;
class GameBoard {

public:
  explicit GameBoard(size_t width = DefaultWidth,
                     size_t height = DefaultHeight);

  GameBoard(const GameBoard &src);
  virtual ~GameBoard();
  GameBoard &operator=(const GameBoard &src);

  std::unique_ptr<GamePiece> &at(size_t x, size_t y);
  const std::unique_ptr<GamePiece> &at(size_t x, size_t y) const;

  size_t getWidth() const { return m_width; };
  size_t getHeight() const { return m_height; }

  static const size_t DefaultWidth{10};
  static const size_t DefaultHeight{10};

  void swap(GameBoard &other) noexcept;

private:
  void verifyCoordinate(size_t x, size_t y) const;
  std::vector<std::vector<std::unique_ptr<GamePiece>>> m_cells;
  size_t m_width{0};
  size_t m_height{0};
};
void swap(GameBoard &first, GameBoard &second) noexcept;
//*/

////////////////// template

class GamePiece;
template <typename T> class Grid {

public:
  explicit Grid(size_t width = DefaultWidth, size_t height = DefaultHeight);

  virtual ~Grid() = default;
  Grid(const Grid &src);
  Grid<T> &operator=(const Grid<T> &src);

  std::optional<T> &at(size_t x, size_t y);
  const std::optional<T> &at(size_t x, size_t y) const;

  size_t getWidth() const { return m_width; };
  size_t getHeight() const { return m_height; }

  static const size_t DefaultWidth{10};
  static const size_t DefaultHeight{10};

  void swap(Grid<T> &other) noexcept;

private:
  void verifyCoordinate(size_t x, size_t y) const;
  std::vector<std::vector<std::optional<T>>> m_cells;
  size_t m_width{0};
  size_t m_height{0};
};
template <typename T> void swap(Grid<T> &first, Grid<T> &second) noexcept;